<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head>
  
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8">

  
  <link href="../css/style.css" rel="stylesheet" type="text/css">

</head>
<body>
<h1>4.11. Условные и безусловные переходы</h1>
<p class="article">В этой части научимся программировать условные и безусловные переходы. Вообще, трудно представить себе программу без проверки условий и переходов. С их помощью в программе реализуются различные управляющие конструкции, ветвления и даже циклы.
</p>
<h2>Безусловные переходы</h2>
<p class="article">Безусловный переход — это переход, который выполняется всегда. Безусловный переход осуществляется с помощью команды JMP. У этой команды один операнд, который может быть непосредственным адресом (меткой), регистром или ячейкой памяти, содержащей адрес. Существуют также «дальние» переходы — между сегментами, однако здесь мы их рассматривать не будем. Примеры безусловных переходов:</p>

<pre class="code">
    jmp metka    ;Переход на метку
    jmp bx       ;Переход по адресу в BX
    jmp word[bx] ;Переход по адресу, содержащемуся в памяти по адресу в BX
</pre>
<h2>Условные переходы</h2>
<p class="article">Условный переход осуществляется, если выполняется определённое условие, заданное флагами процессора (кроме одной команды, которая проверяет CX на равенство нулю). Как вы помните, состояние флагов изменяется после выполнения арифметических, логических и некоторых других команд. Если условие не выполняется, то управление переходит к следующей команде.</p>
<p class="article">Существует много команд для различных условных переходов. Также для некоторых команд есть синонимы (например, JZ и JE — это одно и то же). Для наглядности все команды условных переходов приведены в таблице:</p>
<table>
<tr>
<th>Команда</th>
<th>Переход, если</th>
<th>Условие перехода</th>
</tr>
<tr>
<td>JZ/JE</td>
<td>нуль или равно</td>
<td>ZF=1</td>
</tr>
<tr>
<td>JNZ/JNE</td>
<td>не нуль или не равно</td>
<td>ZF=0</td>
</tr>
<tr>
<td>JC/JNAE/JB</td>
<td>есть переполнение/не выше и не равно/ниже</td>
<td>CF=1</td>
</tr>
<tr>
<td>JNC/JAE/JNB</td>
<td>нет переполнения/выше или равно/не ниже</td>
<td>CF=0</td>
</tr>
<tr>
<td>JP</td>
<td>число единичных бит чётное</td>
<td>PF=1</td>
</tr>
<tr>
<td>JNP</td>
<td>число единичных бит нечётное</td>
<td>PF=0</td>
</tr>
<tr>
<td>JS</td>
<td>знак равен 1</td>
<td>SF=1</td>
</tr>
<tr>
<td>JNS</td>
<td>знак равен 0</td>
<td>SF=0</td>
</tr>
<tr>
<td>JO</td>
<td>есть переполнение</td>
<td>OF=1</td>
</tr>
<tr>
<td>JNO</td>
<td>нет переполнения</td>
<td>OF=0</td>
</tr>
<tr>
<td>JA/JNBE</td>
<td>выше/не ниже и не равно</td>
<td>CF=0 и ZF=0</td>
</tr>
<tr>
<td>JNA/JBE</td>
<td>не выше/ниже или равно</td>
<td>CF=1 или ZF=1</td>
</tr>
<tr>
<td>JG/JNLE</td>
<td>больше/не меньше и не равно</td>
<td>ZF=0 и SF=OF</td>
</tr>
<tr>
<td>JGE/JNL</td>
<td>больше или равно/не меньше</td>
<td>SF=OF</td>
</tr>
<tr>
<td>JL/JNGE</td>
<td>меньше/не больше и не равно</td>
<td>SF≠OF</td>
</tr>
<tr>
<td>JLE/JNG</td>
<td>меньше или равно/не больше</td>
<td>ZF=1 или SF≠OF</td>
</tr>
<tr>
<td>JCXZ</td>
<td>содержимое CX равно нулю</td>
<td>CX=0</td>
</tr>
</table>
<p class="article">
</p>
<p class="article">
У всех этих команд один операнд — имя метки для перехода. Обратите внимание, что некоторые команды применяются для беззнаковых чисел, а другие — для чисел со знаком. Сравнения «выше» и «ниже» относятся к беззнаковым числам, а «больше» и «меньше» — к числам со знаком. Для беззнаковых чисел признаком переполнения будет флаг CF, а соответствующими командами перехода JC и JNC. Для чисел со знаком о переполнении можно судить по состоянию флага OF, поэтому им соответствуют команды перехода JO и JNO. Команды переходов не изменяют значения флагов.</p>
<p class="article">В качестве примера я приведу небольшую программу для сложения двух чисел со знаком с проверкой переполнения. В случае переполнения будет выводиться сообщение об ошибке. Вы можете поменять значения объявленных переменных, чтобы переполнение возникало или не возникало при их сложении, и посмотреть, что будет выводить программа.</p>
<pre class="code">
use16                   ;Генерировать 16-битный код
org 100h                ;Программа начинается с адреса 100h
 
    mov al,[x]          ;AL = x
    add al,[y]          ;AL = x + y
    jo error            ;Переход, если переполнение
    mov ah,09h          ;\
    mov dx,ok_msg       ; > Вывод строки 'OK'
    int 21h             ;/
exit:
    mov ah,09h          ;\
    mov dx,pak          ; > Вывод строки 'Press any key...'
    int 21h             ;/
 
    mov ah,08h          ;\
    int 21h             ;/ Ввод символа
 
    mov ax,4C00h        ;\
    int 21h             ;/ Завершение программы
error:
    mov ah,09h          ;\
    mov dx,err_msg      ; > Вывод сообщения об ошибке
    int 21h             ;/
    jmp exit            ;Переход на метку exit
;----------------------------------------------------------
x         db -89
y         db -55
err_msg   db 'Error: overflow detected.',13,10,'$'
ok_msg    db 'OK',13,10,'$'
pak       db 'Press any key...$'
</pre>
<h2>Команды CMP и TEST</h2>
<p class="article">
Часто для формирования условий переходов используются команды CMP и TEST. Команда CMP предназначена для сравнения чисел. Она выполняется аналогично команде SUB: из первого операнда вычитается второй, но результат не записывается на место первого операнда, изменяются только значения флагов. Например:
</p>
<pre class="code">
cmp al,5     	;Сравнение AL и 5
    jl c1    	;Переход, если AL &lt; 5 (числа со знаком)
cmp al,5     	;Сравнение AL и 5
    jb c1    	;Переход, если AL &lt; 5 (числа без знака)
</pre>
<p class="article">
Команда TEST работает аналогично команде AND, но также результат не сохраняется, изменяются только флаги. С помощью этой команды можно проверить состояние различных битов операнда. Например:
</p>
<pre class="code">
    test bl,00000100b ;Проверить состояние 2-го бита BL
    jz c2             ;Переход, если 2-й бит равен 0
</pre>
<h2>Пример программы</h2>
<p class="article">
Простая программка, которая выводит меню и предлагает пользователю сделать выбор. Для ввода символа используется функция DOS 01h (при вводе символ отображается на экране). В зависимости от введённого символа осуществляется переход на нужный кусок кода. Для разнообразия, я поместил данные в начале программы, а не в конце (кстати, обычно так и делают). Чтобы данные не выполнились как код, перед ними стоит команда безусловного перехода.
</p>
<pre class="code">
use16                   ;Генерировать 16-битный код
org 100h                ;Программа начинается с адреса 100h
    jmp start           ;Безусловный переход на метку start
;----------------------------------------------------------
menu    db '1 - Print hello',13,10
        db '2 - Print go away',13,10
        db '0 - Exit',13,10,'$'
select  db 13,10,'Select>$'
hello   db 13,10,'Hello!',13,10,13,10,'$'
go_away db 13,10,'Go away!',13,10,13,10,'$'
;----------------------------------------------------------
start:
    mov ah,09h          ;\
    mov dx,menu         ; > Вывод меню
    int 21h             ;/
 
select_loop:
    mov ah,09h          ;\
    mov dx,select       ; > Вывод строки 'Select>'
    int 21h             ;/
 
    mov ah,01h          ;Функция DOS 01h - ввод символа
    int 21h             ;Введённый символ помещается в AL
 
    cmp al,'1'          ;Сравнение введённого символа с '1'
    je c1               ;Переход, если равно
    cmp al,'2'          ;Сравнение введённого символа с '2'
    je c2               ;Переход, если равно
    cmp al,'0'          ;Сравнение введённого символа с '0'
    je exit             ;Переход, если равно
    jmp select_loop     ;Безусловный переход
c1:
    mov ah,09h          ;\
    mov dx,hello        ; > Вывод строки 'Hello'
    int 21h             ;/
    jmp start           ;Безусловный переход
c2:
    mov ah,09h          ;\
    mov dx,go_away      ; > Вывод строки 'Go away'
    int 21h             ;/
    jmp start           ;Безусловный переход
exit:
    mov ax,4C00h        ;\
    int 21h             ;/ Завершение программы
</pre>
</body>
</html>
